package com.honghh.bootfirst.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.honghh.bootfirst.entity.InterfaceLog;
import com.honghh.bootfirst.service.InterfaceLogService;
import com.honghh.bootfirst.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * ClassName: InterfaceLogAspect
 * Description:
 *
 * @author honghh
 * @date 2019/03/11 14:54
 */
@Slf4j
@Aspect
@Component
public class InterfaceLogAspect {
    @Resource
    private InterfaceLogService interfaceLogService;

    private static final String REQUEST_TYPE = "log";

    private static final String SUCCESS = "200";

    /**
     * 建立日志对象线程变量
     **/
    private ThreadLocal<InterfaceLog> threadLocal = new ThreadLocal<>();


    @Pointcut("execution(public * com.honghh.bootfirst.controller.*.*(..))")
    public void interfaceLog() {
    }

    @Before(value = "interfaceLog()")
    public void before(JoinPoint point) {
        InterfaceLog interfaceLogDO = new InterfaceLog();
        try {
            //  获取请求对象
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();

            interfaceLogDO.setUrl(request.getRequestURI());
            interfaceLogDO.setRequestType(REQUEST_TYPE);
            // 请求报文
            if (point.getArgs() != null && point.getArgs().length > 0) {
                Object parameterObject = point.getArgs()[0];
                if (parameterObject instanceof String) {
                    interfaceLogDO.setRequestBody((String) parameterObject);
                } else {
                    interfaceLogDO.setRequestBody(JSON.toJSONString(parameterObject));
                }
            }
            interfaceLogDO.setRequestMethod(request.getMethod());
            interfaceLogDO.setRequestDate(new Date());
            interfaceLogDO.setRemoteAddr(IPUtils.getIpAddr(request));
        } catch (Exception e) {
            log.error("Before 日志记录报错！message:{}", e.getMessage());
            e.printStackTrace();
        }
        threadLocal.set(interfaceLogDO);
    }

    @AfterReturning(value = "interfaceLog()", returning = "ret")
    public void after(Object ret) {
        InterfaceLog interfaceLogDO = threadLocal.get();
        try {
            interfaceLogDO.setResponseDate(new Date());
            interfaceLogDO.setResponseBody(JSONObject.toJSONString(ret));
            interfaceLogDO.setResponseStatus(SUCCESS);
            interfaceLogDO.setResponseMessage("成功");
        } catch (Exception e) {
            log.error("AfterReturning 日志记录报错！message:{}", e.getMessage());
            e.printStackTrace();
        }
        interfaceLogService.saveLog(interfaceLogDO);
        threadLocal.remove();
    }

    @AfterThrowing(value = "interfaceLog()", throwing = "throwing")
    public void error(Throwable throwing) {
        InterfaceLog interfaceLogDO = threadLocal.get();
        try {
            //将报错信息写入error字段
            interfaceLogDO.setResponseDate(new Date());
            interfaceLogDO.setResponseMessage(throwing.getMessage());
            interfaceLogDO.setRemark(throwing.getStackTrace().length > 0 ? throwing.getStackTrace()[0].toString() : null);
//            记录自定义的错误状态码
//            if (throwing instanceof ApiException) {
//                interfaceLogDO.setResponseStatus(String.valueOf(((ApiException) throwing).getErrorCode()));
//            }
        } catch (Exception e) {
            log.error("AfterThrowing 日志记录报错！message:{}", e.getMessage());
            e.printStackTrace();
        }
        interfaceLogService.saveLog(interfaceLogDO);
        threadLocal.remove();
    }
}
